<?php

require_once('credentials.php');

class DBSingleton
{
	private static $_singleton = null;
	private $connection;
	
	public static function getInstance() 
	{
		if (is_null (self::$_singleton))
		{
			try
			{
				self::$_singleton = new DBSingleton;
			}
			catch (PDOException $ex)
			{
				if (!$GLOBALS['DEBUG'])
					throw new Exception('Error connecting to the database. Check the credentials.');
			
				throw $ex;
			}
		}
		return self::$_singleton;
	}
	
	private function __construct() 
	{
		$this->connection = new PDO(DB_SERVER, DB_USER, DB_PASS);
	}
	
	public function __call($method, $arguments) 
	{
		try
		{
			return call_user_func_array(array($this->connection, $method), $arguments);
		}
		catch(PDOException $ex)
		{			
			if (!$GLOBALS['DEBUG'])
				throw new Exception('Error in the database, try again and if the problem persists contact with the administrator.');
			throw $ex;
		}
	}
}

class Database
{		
	/**
	* Execute a SELECT query
	* 
	* @param string	$select 	Columns names to select.
	* @param string $from	 	Table name.
	* @param array	$where 		Array with where sentence as array("Name LIKE ?", '%'.$userName.'%', PDO::PARAM_STR).
	* @param string $orderBy 	Column name.
	* @param bool	$desc	 	true if descendant.
	* @param int	$skip	 	Number of skip rows.
	* @param int	$numRows	Number of return rows.
	*
	* @return PDOStatment	Returns PDOStatment with result of query.
	*/
	public static function select($select, $from, $where = null, $orderBy = null, $desc = null, $skip = null, $numRows = null)
	{
		$dbh = DBSingleton::getInstance();
		
		$query = 'SELECT '.$select.' FROM '.$from;
		
		if(!is_null($where) && is_array($where))
		{
			$query = $query.' WHERE ';
			
			for( $i = 0; $i < count($where); $i++)
			{				
				$query = $query.$where[$i][0].' ';
			}
		}
		
		if (!is_null($orderBy))
		{
			$query  = $query.' ORDER BY '.$orderBy;
			if (is_bool($desc) && $desc)
				$query = $query.' DESC';
		}
		
		if (is_numeric($skip))
		{
			$query = $query.' LIMIT '.$skip;
			if(is_numeric($numRows) && $numRows > 0)
			{
				$query = $query.','.$numRows;
			}
			else
			{
				$query = $query.','.PHP_INT_MAX;
			}
		}
		
		$sth = $dbh->prepare($query);
		$j = 1;
		if(!is_null($where) && is_array($where))
		{
			for( $i = 0; $i < count($where); $i++)
			{
				if(isset($where[$i][2]) &&  isset($where[$i][1]))
				{
					$sth->bindParam($j, $where[$i][1], $where[$i][2]);
					$j++;
				}
			}
		}
		
		$res = $sth->execute();
		if(!$res){
                    $error = $sth->errorInfo();
                    return null;
                }
		return $sth;
	}
	
	/**
	* Execute a INSERT query
	* 
	* @param string	$into 		Table name.
	* @param array	$where 		Array with colmns and values sentence as array(ColumnName, Value, ValuesType (ex: PDO::PARAM_STR)).
		*
	* @return PDOStatment	Returns PDOStatment with result of query.
	*/
	public static function insert($into, $values)
	{
		$dbh = DBSingleton::getInstance();
		
		$query = "INSERT INTO $into (";
		
		$params = '';
		
		for( $i = 0; $i < count($values) - 1; $i++)
		{				
			$query = $query.$values[$i][0].',';
			$params = $params.'?,';
		}
		$query = $query.$values[count($values) - 1][0].') VALUES ('.$params.'?)';
		
		$sth = $dbh->prepare($query);
		
		for( $i = 0; $i < count($values); $i++)
		{
			$sth->bindParam($i+1, $values[$i][1], $values[$i][2]);
		}
		
		$res = $sth->execute();
		if(!$res){
                    $error = $sth->errorInfo();
                }
		return $res;
	}
	
	public static function update($table, $values, $where)
	{
		$dbh = DBSingleton::getInstance();
		
		$query = "UPDATE $table SET ";
				
		for( $i = 0; $i < count($values) - 1; $i++)
		{				
			$query = $query.$values[$i][0].'=? ,';
		}
		$query = $query.$values[count($values) - 1][0].'=? ';
		
		$query = $query.' WHERE ';
		
		for( $i = 0; $i < count($where); $i++)
		{				
			$query = $query.$where[$i][0].' ';
		}
		
		$sth = $dbh->prepare($query);
		
		for( $i = 0; $i < count($values); $i++)
		{
			$sth->bindParam($i+1, $values[$i][1], $values[$i][2]);
		}
		
		$paramIndex = count($values) + 1;
		for( $i = 0; $i < count($where); $i++)
		{
			$sth->bindParam($i+$paramIndex, $where[$i][1], $where[$i][2]);
		}
		
		$res = $sth->execute();
		if(!$res){
                    $error = $sth->errorInfo();
                }
		return $res;
	}
	
	public static function remove($table, $where)
	{
		$dbh = DBSingleton::getInstance();
		
		$query = "DELETE FROM $table ";
		
		$query = $query.' WHERE ';
		
		for( $i = 0; $i < count($where); $i++)
		{				
			$query = $query.$where[$i][0].' ';
		}
		
		$sth = $dbh->prepare($query);
		
		for( $i = 0; $i < count($where); $i++)
		{
			$sth->bindParam($i+1, $where[$i][1], $where[$i][2]);
		}
		
		$res = $sth->execute();
		if(!$res){
                    $error = $sth->errorInfo();
                }
		return $res;
	}
        
        public static function customQuery($query, $arguments)
        {
            $dbh = DBSingleton::getInstance();
            
            $sth = $dbh->prepare($query);
            
            for($i = 0; $i < count($arguments); $i++)
                $sth->bindParam($arguments[$i][0], $arguments[$i][1], $arguments[$i][2]);

            $res = $sth->execute();
            if(!$res)
            {
                $error = $sth->errorInfo();
            }
            return $sth;
        }
}
?>